package datatableaux;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;


import entities.concept.*;
import entities.role.Role;
import entities.*;

/**
 * Branch changes can be:
 * 1 conjunction: add labels to current Individual
 * 2 disjunction: add labels to current Individual, make branching node, create branches with one OR, set current branch 
 * //no action. branches are dealt with by stack of branches, ORs are automatically removed when adding another OR.
 * 3 exists: add labels to this Individual, create a successor, add range to successor, relation between ancestor/successor 
 * 4 forall: add labels to this Individual and successors
 * 5 axioms: add labels to current Individual
 * !!!!!!Note!!!!!!
 * If c is already present in the label of an ind, c cannot be removed when reverting the changes!
 * @author j55wu
 *
 */

public class DataBranchChanges {

	
	private static boolean startRecording = false;
	private HashMap<Individual, HashSet<Concept>> addedLabels;
	private HashMap<Individual, HashMap<Role, HashSet<Individual>>> addedRoleRelations;
	private HashMap<Individual, HashSet<Concept>> addedExpandedLabels;
	private HashMap<Individual, HashSet<Concept>> addedUnfoldedLabels;
	private HashSet<Individual> potentialQueueInds;
	
	
	
	public HashSet<Individual> getPotentialQueueInds() {
		return potentialQueueInds;
	}
	public void clearPotentialQueueInds() {
		this.potentialQueueInds.clear();
	}
	
	public void addPotentialQueueInds(Individual ind){
		this.potentialQueueInds.add(ind);
	}
	
	public void clearAddedLabels() {
		this.addedLabels.clear();
	}
	public void clearAddedRoleRelations() {
		this.addedRoleRelations.clear();
	}
	
	public static void setRecordingStatus(boolean t){
		startRecording = t;
	}
	
	public static boolean getRecordingStatus(){
		return startRecording;
	}
	public DataBranchChanges() {
		super();
		this.addedLabels = new HashMap<Individual, HashSet<Concept>>();
		this.addedRoleRelations = new HashMap<Individual, HashMap<Role, HashSet<Individual>>>();
		this.addedExpandedLabels = new HashMap<Individual, HashSet<Concept>>();
		this.addedUnfoldedLabels = new HashMap<Individual, HashSet<Concept>>();
		this.potentialQueueInds = new HashSet<Individual>();
	}
	
	
	public void addToExpandedLabel(Individual n, Concept c){
		if(!addedExpandedLabels.containsKey(n)){
			HashSet<Concept> as = new HashSet<Concept>();
			as.add(c);
			addedExpandedLabels.put(n, as);
		}else{
			if(! n.getExpandedLabels().contains(c)){
				addedExpandedLabels.get(n).add(c);
			}			
		}
	}
	
	public void addToUnfoldedLabels(Individual n, Concept c){
		if(!addedUnfoldedLabels.containsKey(n)){
			HashSet<Concept> as = new HashSet<Concept>();
			as.add(c);
			addedUnfoldedLabels.put(n, as);
		}else{
			if(! n.getUnfolededLabels().contains(c)){
				addedUnfoldedLabels.get(n).add(c);
			}
			
		}
	}
	
	public void addToLabel(Individual nn, Concept c){
		if(!addedLabels.containsKey(nn)){
			HashSet<Concept> as = new HashSet<Concept>();
			as.add(c);
			addedLabels.put(nn, as);
		}else{
			if(! nn.getLabels().contains(c)){
				//if this concept is already in its label, it should not be considered as a change, which would otherwise be removed later.
				addedLabels.get(nn).add(c);
			}			
		}
	}
	
	
	public void removeLabel(){
		if(addedLabels.size()>0){
			for(Individual n:addedLabels.keySet()){
				//remove added labels in n
				n.removeLabels(addedLabels.get(n));
			}
		}
		
		if(addedExpandedLabels.size()>0){
			for(Individual n:addedExpandedLabels.keySet()){
				n.getExpandedLabels().removeAll(addedExpandedLabels.get(n));
			}
		}
		if(addedUnfoldedLabels.size()>0){
			for(Individual n:addedUnfoldedLabels.keySet()){
				n.getUnfolededLabels().removeAll(addedUnfoldedLabels.get(n));
			}
		}
	}
	
	public void addToLabel(Individual n, HashSet<Concept> c){
		for(Concept cc : c){
			this.addToLabel(n, cc);
		}
	}
	
	//m - R -> n
	public void addRoleRelations(Individual a, Role r, Individual b){
		if(addedRoleRelations.containsKey(a)){
			if(addedRoleRelations.get(a).containsKey(r)){
				addedRoleRelations.get(a).get(r).add(b);
			}else{
				//no such role for this ind
				HashSet<Individual> obs = new HashSet<Individual>();
				obs.add(b);
				HashMap<Role, HashSet<Individual>> newmap = addedRoleRelations.get(a);
				newmap.put(r, obs);
			}
		}else{
			//no such n
			HashSet<Individual> obs = new HashSet<Individual>();
			obs.add(b);
			HashMap<Role, HashSet<Individual>> newmap = new HashMap<Role, HashSet<Individual>>();
			newmap.put(r, obs);
			addedRoleRelations.put(a, newmap);
		}
	}
	

	public  void removeRelations(){
			for(Individual n : addedRoleRelations.keySet()){
				HashMap<Role, HashSet<Individual>> newmap = addedRoleRelations.get(n);
//				for(Role r: newmap.keySet()){
//					HashSet<Individual> obs = newmap.get(r);
//					n.removeSucessors(r, obs);
//				}
				for(Entry<Role, HashSet<Individual>> e:newmap.entrySet()){
					Role r = e.getKey();
					HashSet<Individual> obs = newmap.get(r);
					n.removeSucessors(r, obs);
				}
			}
	}
	
	
	
	
}
